//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <elatypes.h>
#include <elapi.h>
#include <pseudo.h>
#include <aura.h>

_ELASTOS_NAMESPACE_USING

extern "C" ECode InitCConsoleIo();
extern "C" ECode UninitCConsoleIo();

extern "C" ECode Environment_Initialize();
extern "C" void  Environment_Destroy();

EXTERN ECode Helper_PKernel_Initialize();
EXTERN void  Helper_PKernel_Destroy();

EXTERN void InitTLS();
EXTERN void UninitTLS();

extern CriticalSection g_staticObjectListLock;
extern CriticalSection g_processExitRoutineListLock;
extern CriticalSection g_LocModListLock;
extern UInt32          s_uDelayLoopCount;

EXTERN_C IDeviceDriver * GetGfxEngineService();
EXTERN_C IDeviceDriver * GetBootModuleMgrDriver();
EXTERN_C IDeviceDriver * GetTouchDriver();
EXTERN_C IDeviceDriver * GetKeypadDriver();
EXTERN_C IDeviceDriver * GetDisplayDriver();
EXTERN_C IDeviceDriver * GetIMEDriver();


EXTERN_C IDeviceDriver * GetFileSystemService();
EXTERN_C ECode LoadModules();
EXTERN_C ECode UnLoadModule(void);

#if defined(_linux)
static ECode RegisterDrivers()
{
    return NOERROR;
}
static void  UnregisterDrivers()
{
    return ;
}
static ECode GetLoopCountPerMicrosecond(UInt32 * pLoopCount)
{
    return NOERROR;
}
#else
static ECode GetLoopCountPerMicrosecond(UInt32 * pLoopCount)
{
    Int64 frequency = 0;
    Int64 startCounter = 0, endCounter = 0;
    Double diffTime;
    UInt32 loopCount = 0;
    ECode ec = NOERROR;

#define TESTCOUNT (100)

    ec = AuraSystem_QueryPerformanceFrequency((Aura_Int64 *)&frequency);
    if (FAILED(ec)) goto E_FAIL_EXIT;
    ec = AuraSystem_QueryPerformanceCounter((Aura_Int64 *)&startCounter);
    if (FAILED(ec)) goto E_FAIL_EXIT;

    for (Int32 i = 0; i < TESTCOUNT; i++);
    ec = AuraSystem_QueryPerformanceCounter((Aura_Int64 *)&endCounter);
    if (FAILED(ec)) goto E_FAIL_EXIT;

    diffTime = ((Double)(endCounter - startCounter) / frequency) * 1000000; // Microseconds.

    loopCount = (UInt32)(TESTCOUNT / diffTime);
    if (!loopCount) {
        loopCount = 1;
    }
    *pLoopCount = loopCount;
    return NOERROR;

E_FAIL_EXIT:
    *pLoopCount = 0;
    return ec;
}

static ECode RegisterDrivers()
{
    ECode ec = NOERROR;

    ec = CPseudoKernel::RegisterRunningObject(
                            L"device:bootmods0",
                            GetBootModuleMgrDriver());
    if (FAILED(ec)) {
        return ec;
    }

    ec = CPseudoKernel::RegisterRunningObject(L"device:ktfsdriver",
                           GetFileSystemService());
    if (FAILED(ec)) {
        return ec;
    }

    ec = LoadModules();
    if (FAILED(ec)) {
        return ec;
    }

    ec = CPseudoKernel::RegisterRunningObject(
                            L"device:touch",
                            GetTouchDriver());
    if (FAILED(ec)) {
        return ec;
    }

//    ec = CPseudoKernel::RegisterRunningObject(
//                            L"device:keypad0",
//                            GetKeypadDriver());
//    if (FAILED(ec)) {
//        return ec;
//    }

    ec = CPseudoKernel::RegisterRunningObject(
                         L"device:ime",
                         GetIMEDriver());
    if (FAILED(ec)) {
         return ec;
    }


    ec = CPseudoKernel::RegisterRunningObject(
                            L"device:display0",
                            GetDisplayDriver());
    if (FAILED(ec)) {
        return ec;
    }

    ec = CPseudoKernel::RegisterRunningObject(
                            L"Grafix",
                            GetGfxEngineService());
    if (FAILED(ec)) {
        return ec;
    }

    return NOERROR;
}

static void  UnregisterDrivers()
{
    CPseudoKernel::UnregisterRunningObject(L"Grafix");
    CPseudoKernel::UnregisterRunningObject(L"device:display0");
//  CPseudoKernel::UnregisterRunningObject(L"device:keypad0");
    CPseudoKernel::UnregisterRunningObject(L"device:ime");
    CPseudoKernel::UnregisterRunningObject(L"device:touch");
//  BUGBUG: UnLoadModule();
    CPseudoKernel::UnregisterRunningObject(L"device:ktfsdriver");
    CPseudoKernel::UnregisterRunningObject(L"device:bootmods0");
}
#endif

Boolean AttachElastosDll()
{
    ECode ec = NOERROR;

    ec = Helper_PKernel_Initialize();
    if (FAILED(ec)) goto E_FAIL_EXIT;

    ec = Environment_Initialize();
    if (FAILED(ec)) goto E_FAIL_EXIT;

    InitTLS();

    ec = GetLoopCountPerMicrosecond(&s_uDelayLoopCount);
    if (FAILED(ec)) goto E_FAIL_EXIT;

    ec = _CCriticalSection_Initialize(&g_staticObjectListLock);
    if (FAILED(ec)) goto E_FAIL_EXIT;

    ec = _CCriticalSection_Initialize(&g_processExitRoutineListLock);
    if (FAILED(ec)) goto E_FAIL_EXIT;

    ec = _CCriticalSection_Initialize(&g_LocModListLock);
    if (FAILED(ec)) goto E_FAIL_EXIT;

    ec = InitCConsoleIo();
    if (FAILED(ec)) goto E_FAIL_EXIT;

    ec = RegisterDrivers();
    if (FAILED(ec)) goto E_FAIL_EXIT;

    return TRUE;

E_FAIL_EXIT:
    return FALSE;
}

void DetachElastosDll()
{
    UnregisterDrivers();

#if _DEBUG
    ECode ec =
#endif
    UninitCConsoleIo();
#if _DEBUG
    if (FAILED(ec)) {
        Aura_printf("failed to uninit consoleIo. (ec =0x%x).\n",ec);
    }
#endif

    _CCriticalSection_Terminate(&g_LocModListLock);
    _CCriticalSection_Terminate(&g_processExitRoutineListLock);
    _CCriticalSection_Terminate(&g_staticObjectListLock);
    UninitTLS();
    Environment_Destroy();
    Helper_PKernel_Destroy();
}

